package com.rpframework.utils;

import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.Transient;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 实体类工具类
 *
 * @author 刘兴
 */
public class EntityUtils {
    public final static Logger log = LoggerFactory.getLogger(EntityUtils.class);

    /**
     * 将javaBean转为map类型，然后返回一个map类型的值
     *
     * @param entity javaBean
     * @return Map格式
     */
    public static Map<String, String> beanToMap(Object entity) {
        Map<String, String> params = new HashMap<>(0);
        try {
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(entity);
            for (int i = 0; i < descriptors.length; i++) {
                String name = descriptors[i].getName();
                if (!StringUtils.equals(name, "class")) {
                    params.put(name, propertyUtilsBean.getNestedProperty(entity, name).toString());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return params;
    }

    /**
     * 获取实体类属性值与属性名
     *
     * @param t             实体类
     * @param isNamingHump  是否使用驼峰命名
     * @param isEmpty       是否将空字符串设置为null
     * @param excludeFields 排除字段
     * @return 键值对
     */
    public static Map<String, Object> getEntityAttrMap(Object t, boolean isEmpty, boolean isNamingHump,
                                                       String... excludeFields) {
        Map<String, Object> map = new HashMap<>();
        Class<? extends Object> clazz = t.getClass();
        getObjectAttr(t, clazz, map, isEmpty, isNamingHump, excludeFields);

        Class<?> superclass = clazz.getSuperclass();
        if (superclass != null) {
            getObjectAttr(t, superclass, map, isEmpty, isNamingHump, excludeFields);
        }

        return map;
    }

    /**
     * 获取对象属性不包含父类
     *
     * @param t             对象
     * @param clazz         class
     * @param map           内容
     * @param isNamingHump  是否使用驼峰命名
     * @param isEmpty       是否将空字符串设置为null
     * @param excludeFields 排除字段
     * @return 键值对 EX:{kCardCode=啊哈哈, kCardName=null}
     */
    public static Map<String, Object> getObjectAttr(Object t, Class<? extends Object> clazz, Map<String, Object> map,
                                                    boolean isEmpty, boolean isNamingHump, String... excludeFields) {
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            boolean isBreak = false, isExclude = false;
            String name = method.getName();

            if (name.startsWith("get")) {
                name = name.substring(3);
                name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
                if (!StringUtil.isBlank(excludeFields)) {
                    for (String excludeField : excludeFields) {
                        if (name.equals(excludeField)) {
                            isExclude = true;
                            break;
                        }
                    }
                }
                if (isExclude) {
                    break;
                }
                Field declaredField;
                try {
                    declaredField = clazz.getDeclaredField(name);
                } catch (NoSuchFieldException | SecurityException e) {
                    throw new RuntimeException(e);
                }
                Annotation[] annotations = declaredField.getAnnotations();
                if (annotations != null) {
                    for (Annotation annotation : annotations) {
                        if (annotation.annotationType().equals(Transient.class)) {
                            isBreak = true;
                            break;
                        }

                    }
                }
                if (!isBreak) {
                    try {
                        Object invoke = method.invoke(t);
                        if (isEmpty) {
                            Class<?> type = declaredField.getType();
                            if (type.equals(String.class)) {
                                String str = (String) invoke;
                                if (str == "") {
                                    invoke = null;
                                }
                            }
                        }
                        if (isNamingHump) {
                            name = javaToNamingHump(name);
                        }
                        map.put(name, invoke);
                    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }

                }
            }
            isBreak = false;

        }
        return map;
    }

    /**
     * java命名规范转驼峰命名 <br>
     * eg:bankCardCode = bank_card_code
     *
     * @param string java字段命名
     * @return 驼峰命名
     */
    public static String javaToNamingHump(String string) {
        String regexStr = "[A-Z]";
        Matcher matcher = Pattern.compile(regexStr).matcher(string);
        StringBuffer sb = new StringBuffer();
        while (matcher.find())

        {
            String g = matcher.group();
            matcher.appendReplacement(sb, "_" + g.toLowerCase());
        }
        matcher.appendTail(sb);
        if (sb.charAt(0) == '_')

        {
            sb.delete(0, 1);
        }
        return sb.toString();

    }

    public class entityMap {
        /**
         * 属性名字
         */
        private String name;
        /**
         * 属性值
         */
        private Object value;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            this.value = value;
        }

    }

    /**
     * 检测实体类属性是否为空
     *
     * @param model  实体
     * @param fields 取消的字段
     * @throws SecurityException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static boolean isBlank(Object model, String... fields) throws NoSuchMethodException, SecurityException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        return isBlank(model, true, fields);
    }

    /**
     * 检测实体类属性是否为空
     *
     * @param model  实体
     * @param fields 取消的字段
     * @throws SecurityException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static boolean isBlank(Object model, boolean stringBlank, String... fields) throws NoSuchMethodException,
            SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class<? extends Object> cls = model.getClass();
        Method[] declaredMethods = cls.getDeclaredMethods();
        for (Method method : declaredMethods) {
            String nameMethod = method.getName();
            if (nameMethod.startsWith("get")) {
                nameMethod = nameMethod.substring(3, nameMethod.length());
                nameMethod = Character.toLowerCase(nameMethod.substring(0).toCharArray()[0])
                        + nameMethod.substring(1, nameMethod.length());
                boolean isMethodBreak = false;
                for (String field : fields) {
                    if (nameMethod.equals(field)) {
                        isMethodBreak = true;
                        break;
                    }
                }
                if (isMethodBreak) {
                    break;
                }
                Object resutl = method.invoke(model);
                if (stringBlank) {
                    if (resutl instanceof String) {
                        String string = (String) resutl;
                        if (StringUtils.isBlank(string)) {
                            return false;
                        } else {
                            break;
                        }
                    }
                } else {
                    if (resutl == null) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * 检测实体类属性是否为空
     *
     * @param model 实体
     * @throws SecurityException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static boolean isBlank(Object model) throws NoSuchMethodException, SecurityException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {
        return isBlank(model, new String[]{});
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {
        class User {
            private String name;
            private Date birthday;

            public String getName() {
                return name;
            }

            public void setName(String name) {
                this.name = name;
            }

            public Date getBirthday() {
                return birthday;
            }

            public void setBirthday(Date birthday) {
                this.birthday = birthday;
            }
        }
        User user = new User();
        user.setName("");
        System.out.println(isBlank(user, false, "birthday"));
    }

    /**
     * 如果有字段ID的话跳过他
     *
     * @param t 实体对象
     * @return 是否为空
     */
    public static boolean isNullById(Object t) {
        boolean isNull = false;
        try {
            isNull = isBlank(t, "id");
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            log.error("检测对象字段是否为空", e);
        }
        return isNull;
    }

    /**
     * 获取已设置值的字段
     *
     * @param entity 实体类
     * @return <字段名,值>
     */
    public static Map<String, Object> fieldValues(Object entity) {

        return null;
    }
}
